package com.linkgie.galaxyframework.httpproxy.core;

import java.util.LinkedList;
import java.util.List;

import org.springframework.util.CollectionUtils;

import com.linkgie.galaxyframework.httpproxy.HttpRequestException;
import com.linkgie.galaxyframework.httpproxy.ParamEntry;
import com.linkgie.galaxyframework.httpproxy.HttpParams;
import com.linkgie.galaxyframework.httpproxy.annotations.RequestParam;
import com.linkgie.galaxyframework.httpproxy.annotations.RequestParamList;

/**
 * 请求参数解析器；
 * 
 * @author haiq
 *
 */
abstract class ParamResolvers {

	public static final RequestParamsResolver NONE_REQUEST_PARAM_RESOLVER = new NoneRequestParamResolver();

	/**
	 * 创建参数标注解析器；
	 * 
	 * @param definitions 方法参数定义；
	 * @return
	 */
	public static RequestParamsResolver createParamMapResolver(
			List<ParamDefinition<RequestParamAnnotation>> reqParamDefinitions,
			List<ParamDefinition<RequestParamListAnnotation>> reqParamMapDefinitions) {
		if ((!CollectionUtils.isEmpty(reqParamDefinitions)) && (!CollectionUtils.isEmpty(reqParamMapDefinitions))) {
			RequestParamsResolver resolver1 = createParamResolver(reqParamDefinitions);
			RequestParamsResolver resolver2 = createParamMapResolver(reqParamMapDefinitions);
			return new MultiRequestParamResolverWrapper(resolver1, resolver2);
		}
		if (!CollectionUtils.isEmpty(reqParamDefinitions)) {
			return createParamResolver(reqParamDefinitions);
		}
		if (!CollectionUtils.isEmpty(reqParamMapDefinitions)) {
			return createParamMapResolver(reqParamMapDefinitions);
		}
		return NONE_REQUEST_PARAM_RESOLVER;
	}

	/**
	 * 创建对标注 {@link RequestParamList} 的参数的解析器；
	 * 
	 * @param definitions 方法参数定义；
	 * @return
	 */
	public static RequestParamsResolver createParamMapResolver(
			List<ParamDefinition<RequestParamListAnnotation>> definitions) {
		return new ParamListResolver(definitions);
	}

	/**
	 * 创建对标注 {@link RequestParam} 的参数的解析器；
	 * 
	 * @param definitions 方法参数定义；
	 * @return
	 */
	public static RequestParamsResolver createParamResolver(List<ParamDefinition<RequestParamAnnotation>> definitions) {
		return new ParamEntryResolver(definitions);
	}

	/**
	 * 参数列表解析器；
	 * <p>
	 * 解析方法的参数列表，将方法参数中由 {@link RequestParamList} 标注一个参数值转换为一组请求参数 {@link HttpParams}；
	 * 
	 * @author haiq
	 *
	 */
	private static class ParamListResolver implements RequestParamsResolver {

		private List<ParamDefinition<RequestParamListAnnotation>> definitions;

		/**
		 * @param definitions
		 */
		public ParamListResolver(List<ParamDefinition<RequestParamListAnnotation>> definitions) {
			this.definitions = new LinkedList<ParamDefinition<RequestParamListAnnotation>>(definitions);
		}

		@Override
		public HttpParams resolve(Object[] args) {
			HttpParams params = new HttpParams();
			for (ParamDefinition<RequestParamListAnnotation> defEntry : definitions) {
				RequestParamListAnnotation def = defEntry.getAnnotation();
				Object argValue = args[defEntry.getArgumentIndex()];
				if (argValue == null && def.isRequired()) {
					throw new HttpRequestException("The required argument object is null!");
				}

				HttpParams extParams = def.getConverter().toProperties(argValue);
				if (extParams.isEmpty()) {
					if (def.isRequired()) {
						throw new HttpRequestException("The required request parameter map is empty!");
					}
					// 非必需参数，忽略空值;
					continue;
				}
				if (extParams != null) {
					// 合并参数；
					params.merge(extParams, def.getPrefix());
				}
			} // End of for;
			return params;
		}

	}

	/**
	 * 单项参数解析器；
	 * <p>
	 * 
	 * 解析方法的参数列表，将方法参数中由 {@link RequestParam} 标注一个参数值转换为一项请求参数 {@link ParamEntry}；
	 * 
	 * @author haiq
	 *
	 */
	private static class ParamEntryResolver implements RequestParamsResolver {

		private List<ParamDefinition<RequestParamAnnotation>> paramDefinitions;

		/**
		 * @param paramDefinitions
		 */
		public ParamEntryResolver(List<ParamDefinition<RequestParamAnnotation>> paramDefinitions) {
			this.paramDefinitions = new LinkedList<ParamDefinition<RequestParamAnnotation>>(paramDefinitions);
		}

		@Override
		public HttpParams resolve(Object[] args) {
			HttpParams params = new HttpParams();
			for (ParamDefinition<RequestParamAnnotation> defEntry : paramDefinitions) {
				RequestParamAnnotation def = defEntry.getAnnotation();
				Object arg = args[defEntry.getArgumentIndex()];
				if (arg == null && def.isRequired()) {
					throw new HttpRequestException("The required argument object is null!");
				}

				resovleParams(def, arg, params);
			} // End of for;
			return params;
		}

		private void resovleParams(RequestParamAnnotation def, Object arg, HttpParams params) {
			if (def.isIterable() && arg != null) {
				if (arg.getClass().isArray()) {
					Object[] valObjs = (Object[]) arg;
					for (Object val : valObjs) {
						resovleParamValue(def, val, params);
					}
				}
			} else {
				resovleParamValue(def, arg, params);
			}
		}

		private void resovleParamValue(RequestParamAnnotation def, Object arg, HttpParams params) {
			String value = def.getConverter().toString(arg);
			if (value == null) {
				if (def.isRequired()) {
					throw new HttpRequestException("The required argument value is null!");
				}
				// not required, and ignore null value;
				return;
			}
			if (value.equals(def.getIgnoreValue())) {
				// ignore ;
				return;
			}
			params.set(def.getName(), value);
		}

	}

	/**
	 * 将多个请求参数解析器的解析结果组合在一起的包装器；
	 * 
	 * @author haiq
	 *
	 */
	private static class MultiRequestParamResolverWrapper implements RequestParamsResolver {

		private RequestParamsResolver[] resolvers;

		public MultiRequestParamResolverWrapper(RequestParamsResolver... resolvers) {
			this.resolvers = resolvers;
		}

		@Override
		public HttpParams resolve(Object[] args) {
			HttpParams params = new HttpParams();
			for (RequestParamsResolver resolver : resolvers) {
				HttpParams extParams = resolver.resolve(args);
				params.merge(extParams);
			}
			return params;
		}

	}

	/**
	 * 空的请求参数解析器；
	 * 
	 * 总是返回空的请求参数；
	 * 
	 * @author haiq
	 *
	 */
	private static class NoneRequestParamResolver implements RequestParamsResolver {

		@Override
		public HttpParams resolve(Object[] args) {
			return new HttpParams();
		}

	}

}
